home *** CD-ROM | disk | FTP | other *** search
/ The PC-SIG Library 10 / The PC-Sig Library - Shareware for the IBM PC and Compatibles (PC-SIG)(Tenth Edition Disks 1-2804)(1991).iso / PC_SIGCD / 13 / 0 / DISK1304.ZIP / PXLLIST.PAS < prev    next >
Pascal/Delphi Source File  |  1988-05-04  |  49KB  |  1,262 lines

  1. {$R+}    {Range checking off}                                         {.CP14}
  2. {$B-}    {Boolean complete evaluation on}
  3. {$S+}    {Stack checking on}
  4. {$I+}    {I/O checking on}
  5. {$N-}    {No numeric coprocessor}
  6.  
  7. Unit PXLLIST;
  8.  
  9. Interface
  10.  
  11. Uses
  12.   Crt,
  13.   Dos,
  14.   PXLINIT;
  15.  
  16. procedure ListIt;
  17.  
  18. {===========================================================================}
  19.  
  20. Implementation
  21.  
  22. procedure ListIt;                                                     {.CP10}
  23. const
  24.    TableSize               = 2521;
  25.    Digits                  = 5;
  26.    ProcName                = #158;
  27.    TabChr                  = #0;
  28.    AtStart:    set of char = ['A'..'Z'];
  29.    MiddleSet:  set of char = ['A'..'Z','0'..'9','_'];
  30.    HexNumbers: set of char = ['A'..'F','0'..'9'];
  31.    NumZ9:      set of char = ['0'..'9'];
  32.    Num19:      set of char = ['1'..'9'];
  33.    MaxHeader = 5;
  34. type                                                                  {.CP20}
  35.    Ref          =   ^Item;
  36.    WPt          =   ^WordType;
  37.    TableNum     =   0..TableSize;
  38.    WordType     =   record
  39.                        Key:    Str20;
  40.                        Name:   Str20;
  41.                        First:  Ref;
  42.                     end;
  43.    Item         =   record
  44.                        LinNum: 0..MaxInt;
  45.                        Next:   Ref;
  46.                     end;
  47.    Incs        =    (CantFind,TooDeep,Started,Ended,OK);
  48.    HdSegType   =    (Left,Center,Right);
  49.    HdPgType    =    (First,Other);
  50.    HdLineType  =    array[Left..Right] of LineType;
  51.    HdType      =    array[1..MaxHeader] of HdLineType;
  52.    HeaderType  =    array[First..Other] of HdType;
  53. var                                                                   {.CP22}
  54.    Header:         HeaderType;
  55.    NumOfWords:     TableNum;
  56.    T:              array[TableNum] of WPt;
  57.    Tp:             WPt;
  58.    MaxLess,
  59.    Max,Longest,
  60.    ScanCount,K,
  61.    Occur,PCount,
  62.    Pager,Depth:    integer;
  63.    Cut,Uncut:      Str2;
  64.    Cuts,Uncuts:    array[1..3] of Str2;
  65.    OpLen,ClLen,
  66.    B,Inrec:        byte;
  67.    RecDepth,
  68.    CaseDepth:      array[1..20] of byte;
  69.    IncLine,
  70.    LineEnd,UC:     str255;
  71.    IncMark:        string[8];
  72.    Elite,Condensed,
  73.    LongOne,NoLine: boolean;
  74.    IncState:       Incs;
  75.  
  76.    procedure BlankHeaderLines;                                        {.CP10}
  77.    var
  78.       LNo:    integer;
  79.       HS:     HdSegType;
  80.    begin
  81.       for LNo := 1 to MaxHeader do
  82.          for HS := Left to Right do
  83.             Header[First][LNo,HS] := '';
  84.       Header[Other] := Header[First]
  85.    end; {BlankHeaderLines}
  86.  
  87.    function IsBlank(HL: HdLineType): boolean;                          {.CP8}
  88.    var
  89.       Sg: HdSegType;
  90.    begin
  91.       IsBlank := True;
  92.       for Sg := Left to Right do
  93.          if HL[Sg]<>'' then IsBlank := False
  94.    end; {IsBlank}
  95.  
  96.    function HeaderLineNo(var H: HdType):integer;                       {.CP8}
  97.    var
  98.       Nr: integer;
  99.    begin
  100.       Nr := MaxHeader;
  101.       while (Nr>0) and IsBlank(H[Nr]) do dec(Nr);
  102.       HeaderLineNo := Nr
  103.    end; {HeaderLineNo}
  104.  
  105.    procedure GetHeaderInstruction(Line: string);                      {.CP24}
  106.       (*
  107.       What this is supposed to do:
  108.          "{" + ".H" triggers header function.  Possibilities are
  109.          .HN  = no header at all
  110.          .HnL = Left side of Header line #n
  111.          .HnC = Center of Header line #n
  112.          .HnR = Right side of Header line #n
  113.          .HnN = No Header line #n  (Has no effect in PXL.HDR or Top Lines)
  114.          .HPLnn = nn lines per page (default is 66 - BottomMargin)
  115.       Text for header line segment begins 1 col AFTER end of symbol
  116.       Within header line text:
  117.          .Fn = file name
  118.          .Fd = file date (long date)
  119.          .Ft = file time (12 hr am/pm)
  120.          .Pd = present (or printout) date (numeral)
  121.          .Pd = present (or printout) time (24 hr)
  122.          .Id = ID (from PXL.ID)
  123.           #  = page number
  124.        *)
  125.    var
  126.       IStrg: LineType;
  127.       Cue:   Str3;
  128.       Col:   integer;
  129.  
  130.       procedure ResetMaxLin(S: LineType);                             {.CP24}
  131.       {This is activated by an .HPLnn command in the text or in PXL.HDR.}
  132.       {Be careful.  It sets the number of lines printed, not the length }
  133.       {of the paper.  It will override the BottomMargin set in PXL.PAS. }
  134.       {If your printer is set up to put fewer than the number set here, }
  135.       {you get a mess.  Ordinarily, strange paper sizes can be set with }
  136.       {PXLINST, provided you can forego FF's.                           }
  137.       var
  138.          NumStr: Str20;
  139.          K,E:    integer;
  140.       begin
  141.          if S[1]='L' then begin
  142.             K := 2;
  143.             NumStr := '';
  144.             while (S[K] in NumZ9) and (K<=ord(S[0])) do begin
  145.                NumStr := NumStr + S[K];
  146.                inc(K)
  147.             end; {while 0..9}
  148.             if NumStr[0]>#0 then val(NumStr,K,E);
  149.             if (K>0) and (E=0) then MaxLin := K        {if error, do nothing}
  150.          end {if L}
  151.       end; {ResetMaxLin}
  152.  
  153.       function FixedUpHeaderLine(L: LineType): string;                {.CP10}
  154.       begin
  155.          while pos('.Fn',L)>0 do Replace('.Fn',FileName,L);
  156.          while pos('.Fd',L)>0 do Replace('.Fd',FileDate,L);
  157.          while pos('.Pd',L)>0 do Replace('.Pd',PrintDate,L);
  158.          while pos('.Ft',L)>0 do Replace('.Ft',FileTime,L);
  159.          while pos('.Pt',L)>0 do Replace('.Pt',PrintTime,L);
  160.          while pos('.Id',L)>0 do Replace('.Id',UserID,L);
  161.          FixedUpHeaderLine := L
  162.       end; {FixedUpHeaderLine}
  163.  
  164.       procedure InterpretInstruction(Strg: LineType);                 {.CP17}
  165.       const
  166.          Symbols:  set of char = ['C','L','N','R'];
  167.       var
  168.          HNo:  byte;
  169.          HSg:  HdSegType;
  170.          C:    char;
  171.          Pg:   HdPgType;
  172.  
  173.       begin {InterpretInstruction}
  174.         C := Strg[1];
  175.         delete(Strg,1,1);
  176.         if C='N' then
  177.            BlankHeaderLines
  178.         else if C='P' then
  179.            ResetMaxLin(Strg)
  180.         else if C in Num19 then begin                            {.CP28}
  181.            HNo := ord(C) - $30;
  182.            if HNo<1 then HNo := 1;
  183.            if HNo>MaxHeader then HNo := MaxHeader;
  184.            C := Strg[1];
  185.            delete(Strg,1,2);        {eat both this char and delimiting space}
  186.            if C in Symbols then begin
  187.               if C='N' then begin
  188.                  if (Page<2) and IsBlank(Header[Other][HNo])
  189.                     then Pg := First
  190.                     else Pg := Other;
  191.                  for HSg := Left to Right do Header[Pg][HNo,HSg] := ''
  192.               end {if N}
  193.               else begin
  194.                  case C of
  195.                     'L':  HSg := Left;
  196.                     'C':  HSg := Center;
  197.                     'R':  HSg := Right;
  198.                  end; {case}
  199.                  Strg := FixedUpHeaderLine(Strg);
  200.                  if (Page>1) or (Header[First][HNo,HSg]<>'')
  201.             then Pg := Other
  202.             else Pg := First;
  203.          for Pg := Pg to Other do Header[Pg][HNo,HSg] := Strg;
  204.               end {else not N}
  205.            end {if Symbol}
  206.         end {else if 1..9}
  207.       end; {InterpretInstruction}
  208.  
  209.    begin {GetHeaderInstruction}                                     {.CP13}
  210.       Cue := '{' + '.H';
  211.       while pos(Cue,Line)>0 do begin
  212.          Col := pos(Cue,Line) + 3;
  213.          IStrg := '';
  214.          while (Line[Col]<>'}') and (Col<=ord(Line[0])) do begin
  215.             IStrg := IStrg + Line[Col];
  216.             inc(Col)
  217.          end; {while}
  218.          Line := Copy(Line,succ(Col),255);
  219.          InterpretInstruction(IStrg)
  220.       end {while}
  221.    end; {GetHeaderInstruction}
  222.  
  223.    function HeaderLine(H: HdLineType): LineType;                     {.CP21}
  224.    var
  225.       Spaces,K: integer;
  226.       Temp:     LineType;
  227.       Pg:       HdPgType;
  228.       Sg:       HdSegType;   C: char;
  229.    begin
  230.       Temp := '';
  231.       if Page<2
  232.          then Pg := First
  233.          else Pg := Other;
  234.       for Sg := Left to Right do         {Must update page number every page}
  235.          while pos('#',H[Sg])>0  do
  236.             Replace('#',StrgI(Page,1),H[Sg]);
  237.       repeat               {Splice left & right segs --chopping if necessary}
  238.          Spaces := ord(H[Left,0]) + ord(H[Right,0]);
  239.          if Spaces>79 then begin
  240.              if H[Right,0]>#0 then delete(H[Right],1,1)
  241.              else if H[Left,0]>#0 then dec(H[Left,0])
  242.          end {if Spaces}
  243.       until Spaces<=79;
  244.       Temp := H[Left];           {Overprint line with Center segment} {.CP10}
  245.       for K := 1 to (79 - Spaces) do Temp := Temp + #32;
  246.       Temp := Temp + H[Right];
  247.       if H[Center]<>'' then begin
  248.          Spaces :=  39 - (ord(H[Center,0]) div 2);
  249.          for K := 1 to ord(H[Center,0]) do
  250.             Temp[K+Spaces] := H[Center,K]
  251.       end; {if Center}
  252.       HeaderLine := Temp;
  253.    end; {HeaderLine}
  254.  
  255.    procedure MakeFirstHeader(var Fil: text);                          {.CP25}
  256.    var
  257.       Lin:    Str255;
  258.  
  259.       function GotDefaultHeaderFromFile: boolean;
  260.       var
  261.          FName:  LineType;
  262.          F:      text;
  263.       begin
  264.          FName := 'PXL.HDR';
  265.          if FindFile(FName) then begin
  266.             assign(F,FName);
  267.             reset(F);
  268.             while not Eof(F) do begin
  269.                readln(F,Lin);
  270.                if pos('{' + '.H',Lin)<>0 then begin
  271.                   GetHeaderInstruction(Lin)
  272.                end {if Cue}
  273.             end; {while not Eof}
  274.             close(F);
  275.             GotDefaultHeaderFromFile := True
  276.          end {if FindFile}
  277.          else
  278.             GotDefaultHeaderFromFile := False
  279.       end; {GotDefaultHeaderFromFile}
  280.  
  281.       procedure MakeStandardDefaultHeader;                            {.CP14}
  282.       begin
  283.          Header[First][1,Right] := FileTime + ', ' + FileDate;
  284.          if XRefOnly
  285.             then Header[First][1,Left] :='Cross-Reference of: '
  286.             else Header[First][1,Left] := 'File: ';
  287.          Header[First][1,Left] := Header[First][1,Left] + FileName;
  288.          if UserID[0]>#0 then
  289.             Header[First][1,Left] := Header[First][1,Left]
  290.                                      + '  [' + UserID + ']';
  291.          Header[Other][1] := Header[First][1];
  292.          Header[Other][1,Right] := 'Page #' (* + StrgI(Page,1); *)
  293.       end; {MakeStandardDefaultHeader}
  294.  
  295.       procedure LoadFirstHeader(var F: text);                         {.CP16}
  296.       var
  297.          L:      string;
  298.          B,Col:  byte;
  299.       begin
  300.          reset(Fil);
  301.          repeat
  302.             readln(Fil,L);
  303.             B := pos('{'+'.H',L);
  304.             if B>0 then begin
  305.                GetHeaderInstruction(L);
  306.                delete(L,1,B);
  307.                while (L[1]<>'}') and (L[0]<>#0)  do delete(L,1,1)
  308.             end {if >0}
  309.          until B=0;
  310.       end; {LoadFirstHeader}
  311.  
  312.    begin {MakeFirstHeader}                                             {.CP9}
  313.       BlankHeaderLines;
  314.       if not GotDefaultHeaderFromFile then MakeStandardDefaultHeader;
  315.       reset(Fil);
  316.       readln(Fil,Lin);
  317.       if pos('{'+'.H',Lin)<>0 then LoadFirstHeader(F);    {Check top of file}
  318.       reset(Fil);                                {Return file open but reset}
  319.       PageLineNumber := HeaderLineNo(Header[First]) + 2;
  320.    end; {MakeFirstHeader}
  321.  
  322.    procedure PrintHeader(var PLine: integer); {Print header line(s)}  {.CP21}
  323.    var
  324.       Line:   String;
  325.       K,Nr:   integer;
  326.       Pg:     HdPgType;
  327.    begin
  328.       {$I-}
  329.       writeln(Lst);
  330.       {$I+}
  331.       if not (IOresult=0) then
  332.          CantCont('','Printer''s out');
  333.       Line := '';
  334.       if GotPrnData then
  335.          if Wide then                                  {Set normal Pica}
  336.             write(Lst,Istring[CondE])
  337.          else if Numberlines then
  338.             write(Lst,Istring[EliteE]);
  339.       if Page<2
  340.          then Pg := First
  341.          else Pg := Other;
  342.       Nr := HeaderLineNo(Header[Pg]);
  343.       for K := 1 to Nr do                                             {.CP13}
  344.          writeln(Lst,HeaderLine(Header[Pg][K]));
  345.       if GotPrnData then
  346.          if Wide then                                 {Set Condensed type}
  347.             write(Lst,Istring[CondB])
  348.          else if NumberLines then                     {or Elite}
  349.             write(Lst,Istring[EliteB]);
  350.       writeln(Lst);
  351.       inc(Page);
  352.       PLine := 2 + Nr;
  353.    end; {PrintHeader}
  354.  
  355.    procedure PrintControl(var PageLineNumber: integer);               {.CP21}
  356.    var
  357.       Sym: string[8];
  358.       I, J, Err: integer;
  359.    begin
  360.       if pos(concat('{.','PA}'),Line)<>0 then
  361.          PageLineNumber := succ(MaxLin)
  362.       else if pos(concat('{.','CP'),Line) <>0 then begin
  363.          I := pos(concat('{.','CP'),Line) + 4;
  364.          Sym := '';
  365.          while Line[I] in NumZ9 do begin
  366.             Sym := concat(Sym,Line[I]);
  367.             I := succ(I);
  368.          end {while};
  369.          val(Sym,I,Err);
  370.          if Err<>0 then I := 0;  {in case print control symbol is bungled}
  371.          if PageLineNumber > (MaxLin-I) then PageLineNumber := succ(MaxLin);
  372.       end {if}
  373.    end; {PrintControl}
  374.  
  375.    procedure ReadingMatterI;                                          {.CP12}
  376.    begin
  377.       Blank(9,12);
  378.       if not Xref then
  379.          CenterCRT('Sending ' + FileName + ' to ' + OutputDevice,
  380.                10,Bright,0)
  381.       else if not XRefOnly then
  382.          CenterCRT('Scanning ' + FileName + ' and sending to '
  383.                + OutputDevice + '.', 10,Bright,0)
  384.       else
  385.          CenterCRT('Scanning ' +  FileName,10,Bright,0)
  386.    end; {ReadingMatterI}
  387.  
  388.    procedure ReadingMatterII;                                          {.CP5}
  389.    begin
  390.       CenterCRT('Sending cross-reference to ' + OutputDevice,
  391.                 10,Bright,Inside)
  392.    end; {ReadingMatterII}
  393.  
  394.    procedure NewPage(Pager: integer);                                 {.CP15}
  395.    var
  396.       I:           integer;
  397.    begin
  398. (*      {$I-}
  399.       writeln(Lst);
  400.       {$I-}
  401.       if IOresult<>0 then CantCont('','Printer''s out.'); *)
  402.       if Inst[FF,1]=12 then begin
  403.          {$I-}
  404.          write(Lst,#12);
  405.          {$I-}
  406.          if IOresult<>0 then CantCont('','Printer''s out.');
  407.       end {if FF}
  408.       else begin
  409.          {$I-}
  410.          writeln(Lst);
  411.          {$I-}
  412.          if IOresult<>0 then CantCont('','Printer''s out.');
  413.          for I := succ(Pager) to Inst[FF,1] do writeln(Lst);
  414.       end {no FF}
  415.    end; {NewPage}
  416.  
  417.    procedure PrintTable;                                              {.CP17}
  418.    type
  419.       ProcPtr   =  ^ProcWord;
  420.       ProcWord  =  record
  421.                       Name:   Str20;
  422.                       LinNum: 0..MaxInt;
  423.                       Next:   ProcPtr;
  424.                    end;
  425.    var
  426.       I:           TableNum;
  427.       Lin:         integer;
  428.       NumPerLine:  byte;
  429.       PL:          record
  430.                       First: ProcPtr;
  431.                       Last:  ProcPtr;
  432.                    end;
  433.       PLptr:       ProcPtr;
  434.  
  435.       procedure Compress(var N: TableNum);                            {.CP11}
  436.       var
  437.          I: TableNum;
  438.       begin
  439.          N := 0;
  440.          for I := 0 to TableSize do
  441.             if T[I] <> Nil then begin
  442.                T[N] := T[I];
  443.                inc(N)
  444.             end; {if T[I]}
  445.       end; {Compress}
  446.  
  447.       procedure Sort(Lo, Hi: integer); {Quicksort}                    {.CP31}
  448.       var
  449.          Low,High: TableNum;
  450.          Mid,Temp: WPt;
  451.       begin
  452.          repeat                                 {Pick split points}
  453.             Mid := T[(Lo+Hi) div 2];
  454.             Low := Lo;
  455.             High := Hi;
  456.             repeat                                 {partitions}
  457.                while T[Low]^.Key<Mid^.Key do Inc(Low);
  458.                while T[High]^.Key>Mid^.Key do dec(High);
  459.                if Low<=High then begin
  460.                   Temp := T[Low];
  461.                   T[Low] := T[High];
  462.                   T[High] := Temp;
  463.                   if Low<TableSize then inc(Low);
  464.                   if High>0 then dec(High)
  465.                end {if Low<=}
  466.             until Low > High;
  467.             {recursively sort shorter sub-segment}
  468.             if (High-lo) < (Hi-Low) then begin
  469.                if Lo < High then Sort(Lo,High);
  470.                Lo := Low
  471.             end {if (High}
  472.             else begin
  473.                if Low < Hi then Sort(Low,Hi);
  474.                Hi := High;
  475.             end {else}
  476.          until Hi <= Lo
  477.       end; {Sort}
  478.  
  479.       procedure PageOut;                                               {.CP7}
  480.       begin
  481.          NewPage(Lin);
  482.          PrintHeader(Lin);
  483.          writeln(Lst);
  484.          inc(Lin)
  485.       end; {PageOut}
  486.  
  487.       procedure PrintWord(W: WordType);                               {.CP20}
  488.       var
  489.          X,Y,Z:      Ref;
  490.          Num:        integer;
  491.          B:          byte;
  492.  
  493.       procedure ProcProc; {Add new proc/func name to list}
  494.       begin
  495.          Delete(W.Name,1,1);                          {remove tell-tale mark}
  496.          New(PLptr);
  497.          PLptr^.Name := W.Name;
  498.          PLptr^.LinNum := X^.LinNum;
  499.          PLptr^.Next := Nil;
  500.          if PL.First = Nil then begin
  501.             PL.First := PLptr;
  502.             PL.Last := PLptr
  503.          end; {if first procedure}
  504.          PL.Last^.Next := PLptr;
  505.          PL.Last := PLptr
  506.       end; {ProcProc}
  507.  
  508.       begin {PrintWord}                                               {.CP10}
  509.          if Lin>MaxLin then PageOut;
  510.          X := W.First; Y := X^.Next; X^.Next := Nil;
  511.          while Y<>Nil do begin         {inky pinky pider, reversing pointers}
  512.             Z := Y^.Next; Y^.Next := X; X := Y; Y := Z;
  513.          end; {while Y<>Nil}
  514.          Num := 0;
  515.          if W.Name[1]=ProcName then ProcProc;         {add to proc/func list}
  516.          Write(Lst,#32,W.Name);
  517.          for B := 1 to Longest-ord(W.Name[0]) do write(Lst,#32);
  518.          repeat                                  {write line numbers} {.CP21}
  519.             if Num=NumPerLine then begin              {new line if necessary}
  520.                Num := 0;
  521.                writeln(Lst);
  522.                inc(Lin);
  523.                if Lin>MaxLin then begin
  524.                   PageOut;
  525.                   Write(Lst,#32,W.Name);
  526.                   for B := 1 to Longest-ord(W.Name[0]) do
  527.                      write(Lst,#32)
  528.                end {if Lin}
  529.                else
  530.                   Write(Lst,#32:(succ(Longest)))
  531.             end; {if Num}
  532.             inc(Num);
  533.             write(Lst,X^.LinNum:Digits);
  534.             X := X^.Next
  535.          until X=Nil;
  536.          writeln(Lst);
  537.          inc(Lin)
  538.       end; {PrintWord}
  539.  
  540.       procedure PrintPL;  {Print list of procedures & functions}      {.CP15}
  541.       var
  542.          B:     byte;
  543.  
  544.          procedure PrintAProc;             {print one line in proc/func list}
  545.          var
  546.             B: byte;
  547.          begin
  548.             write(Lst,#32,PL.First^.Name);
  549.             for B := 1 to Longest-ord(PL.First^.Name[0]) do write(Lst,#32);
  550.             writeln(Lst,PL.First^.LinNum:Digits);
  551.             inc(I);
  552.             GotoXY(30,16);
  553.             Write(I:5);
  554.             PL.First := PL.First^.Next;
  555.          end; {PrintAProc}
  556.  
  557.       begin {PrintPL}                                                 {.CP19}
  558.          if (Lin+PCount+5) > MaxLin then
  559.             PageOut
  560.          else begin
  561.             writeln(Lst);
  562.             inc(Lin)
  563.          end; {else}
  564.          writeln(Lst,'Procedures and Functions:');
  565.          writeln(Lst);
  566.          if PL.First=PL.Last then              {Just one proc/func in list}
  567.             PrintAProc
  568.          else
  569.             while (PL.First<>Nil) and not enough do begin
  570.                inc(Lin);
  571.                if Lin > MaxLin then PageOut;
  572.                PrintAProc;
  573.                Enough := Escape
  574.             end {while}
  575.       end; {PrintPL}
  576.  
  577.    begin {PrintTable}                                                 {.CP15}
  578.       if NumberLines then
  579.          if Mrk then Max := Max+10 {take account of space for beg/end count}
  580.          else Max := Max + 6;
  581.       NumPerLine := (Max-Longest) div Digits;
  582.       PL.First := Nil; PL.Last := Nil;
  583.       Compress(NumOfWords);
  584.       Sort(0,pred(NumOfWords));
  585.       PrintHeader(Lin);
  586.       writeln(Lst);
  587.       writeln(Lst,'Crosslisting of Identifiers:');
  588.       writeln(Lst);
  589.       WriteCRT('X-Ref Lines:   ',16,15,Bright);
  590.       Lin := Lin + 3;
  591.       I := 0;
  592.       while (I<NumOfWords) and not Enough do begin {print XRef lines} {.CP15}
  593.          PrintWord(T[I]^);
  594.          inc(I);
  595.          GotoXY(30,16); write(I:5);                   {keep user entertained}
  596.          Enough := Escape
  597.       end; {while}
  598.       if (PCount>0) and not Enough then PrintPL;
  599.       writeln(Lst);
  600.       write(Lst,'Lines: ',LineNumber,'    Identifiers: ',ScanCount,
  601.          '    Occurrences: ',Occur);
  602.       if PCount>0 then
  603.          writeln(Lst,'    Procedures: ',PCount)
  604.       else
  605.          writeln(Lst)
  606.    end; {PrintTable}
  607.  
  608.    procedure ScanAndHash(var UC,Line: Str255; LinNo: integer);        {.CP18}
  609.    var
  610.       Ident:      WordType;
  611.       Len,I:      byte;
  612.       Col:        integer;
  613.       ProcOrFunc: boolean;
  614.  
  615.       procedure Calamity;
  616.       begin
  617.          ClrScr;
  618.          PXLRectangle;
  619.          CenterCRT('CALAMITY',11,Bright,0);
  620.          WriteCRT('Too many @$#%'+#237+'@! identifiers',13,25,Bright);
  621.          WriteCRT('    I can''t handle that.',14,25,Bright);
  622.          CloseCarefully(F);
  623.          RestoreScreen;
  624.          Halt
  625.       end; {Calamity}
  626.  
  627.       procedure Hash(Ident: WordType);                                 {.CP17}
  628.       var
  629.          Found:     boolean;
  630.          ID:        record
  631.                        case byte of
  632.                           1: (Key: str20);
  633.                           2: (O:   integer);
  634.                           3: (Arr: array[0..20] of byte);
  635.                     end;
  636.          X:         Ref;
  637.          H,D,Start: TableNum;
  638.       begin
  639.          ID.Key := Ident.Key;
  640.          inc(Occur);
  641.          H := abs(ID.O) mod TableSize;        {hash using 1st 2 bytes of key}
  642.          Start := H;
  643.          new(X); X^.LinNum := LinNo; Start := H; D := 1;
  644.          repeat                                                       {.CP26}
  645.             if T[H]^.Key = ID.Key then begin          {found the Key        }
  646.                Found := True;
  647.                X^.Next := T[H]^.First;                   {add line # to list}
  648.                T[H]^.First := X
  649.             end {if found key}
  650.             else if T[H] = Nil then begin             {empty place --new key}
  651.                Found := True;
  652.                inc(ScanCount);                            {count it         }
  653.                if ord(ID.Key[0])>Longest then             {update Longest   }
  654.                    Longest := ord(ID.Key[0]);
  655.                New(Tp);
  656.                Tp^.Key := ID.Key;                         {set up new key   }
  657.                Tp^.Name := Ident.Name;                    {and name         }
  658.                Tp^.First := X;                            {and first line # }
  659.                T[H] := Tp;                                {& put in hash tbl}
  660.                X^.Next := Nil
  661.             end {else if new}
  662.             else begin                                {place occupied       }
  663.                Found := False;
  664.                H := H + ID.Arr[ID.Arr[0]];   {re-hash using last byte of key}
  665.                if H>=TableSize then H := H - TableSize;
  666.                if H=Start then Calamity
  667.             end {else --place otherwise occupied}
  668.          until Found
  669.       end; {Hash}
  670.  
  671.    begin  {ScanAndHash}                                               {.CP16}
  672.       GotoXY(30,14); write(LinNo:5);                  {keep user entertained}
  673.       Col := 1; ProcOrFunc := False;
  674.       Len := ord(UC[0]);
  675.       while Col<=Len do begin                                {creep along UC}
  676.          if UC[Col]<>#32 then begin                  {looking for non-blanks}
  677.             if UC[Col] <> ProcName then begin   {if a normal character      }
  678.                Ident.Key := ''; Ident.Name := '';
  679.                I := Col + 20;                    {20 chars is max key length}
  680.                while (UC[Col]<>#32) and (Col<=Len) do begin {read non-blanks}
  681.                   if Col<I then begin
  682.                      Ident.Key := Ident.Key + UC[Col];
  683.                      Ident.Name := Ident.Name + Line[Col]
  684.                   end; {if Col}
  685.                   inc(Col);
  686.                end; {while}
  687.                if ProcOrFunc then begin     {.CP15} {if it's a new procedure}
  688.                   insert(ProcName,Ident.Name,1);       {mark the Name       }
  689.                   ProcOrFunc := False
  690.                end; {if ProcOrFunc}
  691.                Hash(Ident)                          {put into the hash table}
  692.             end {if not ProcName}
  693.             else begin                           {if it's the Procedure sign}
  694.                ProcOrFunc := True;
  695.                inc(Col)
  696.             end {else --ProcName}
  697.          end {if not blank}
  698.          else
  699.             inc(Col);
  700.       end {while}
  701.    end; {ScanAndHash}
  702.  
  703.    procedure Underline (var Line: Str255);                            {.CP19}
  704.    var
  705.       K,J:         integer;
  706.       B:           byte;
  707.       InMiddle,
  708.       InHex:    Boolean;
  709.  
  710.       procedure Ins (var Line,UC :Str255; Op,Cl:Str3);
  711.       var
  712.          Z,Len,B:     byte;
  713.          K,Col:       integer;
  714.          ShdBeMarked: boolean;
  715.          Obj:         Str10;
  716.       begin {Ins}
  717.          for K := 1 to NRes do begin            {Check against Key word list}
  718.             if Pos(Reserv[K],UC)<>0 then begin     {if Key word is in line  }
  719.                Obj := Reserv[K];
  720.                Col := pos(Obj,UC);
  721.                Len := ord(Obj[0]);
  722.                repeat                                                 {.CP15}
  723.                   if (UC[pred(Col)]=#32) and               {if surroundings OK  }
  724.                      (UC[Col+Len]=#32) then begin
  725.                      insert(Cl,Line,Col+Len);              {Insert Closing  }
  726.                      insert(Op,Line,Col);                  {Insert Opening  }
  727.                      for B := Col to Col+pred(Len) do      {blank Obj in UC }
  728.                         UC[B] := #32;
  729.                      if Xref and (Obj='PROCEDURE')
  730.                         or (Obj='FUNCTION') then begin     {Mark Proc & Func}
  731.                         inc(PCount);
  732.                         UC[Col+OpLen] := ProcName
  733.                      end; {if XRef &}
  734.                      for B := 1 to OpLen+ClLen do     {Blanks to match up UC}
  735.                         insert(#32,UC,Col);
  736.                      Col := Col + Len + OpLen + ClLen;   {move to end of Obj}
  737.                      if NumberLines then begin                        {.CP23}
  738.                         if (Obj='BEGIN') or
  739.                         (Obj='REPEAT') or (Obj='CASE') then {count begin/end}
  740.                            inc(Depth)
  741.                         else if (Obj='END')  then begin {Style Critics: Yes,}
  742.                            if InRec=0 then              {this should be a   }
  743.                               dec(Depth)                {procedure in itself}
  744.                            else begin                   {but, in so busy a  }
  745.                               Depth := RecDepth[InRec]; {loop, we must avoid}
  746.                               dec(InRec)                {overhead.          }
  747.                            end {else if InRec}
  748.                         end {else if END}
  749.                         else if (Obj='UNTIL') then
  750.                            dec(Depth)
  751.                         else if Obj='RECORD' then begin
  752.                            inc(InRec);
  753.                            RecDepth[InRec] := Depth;
  754.                            inc(Depth)
  755.                         end {else if RECORD}
  756.                      end; {if NumberLines}
  757.                   end {if surroundings Okay}
  758.                   else
  759.                      Col := Col + Len;                    {move Col past obj}
  760.                   if Col>(ord(Line[0])-succ(Len)) then                {.CP13}
  761.                      ShdBeMarked := False
  762.                   else begin                                       {Another?}
  763.                      B := pos(Obj,copy(UC,succ(Col),ord(UC[0])-Col));  {.CP9}
  764.                      if B=0 then                         {No, so         }
  765.                         ShdBeMarked := False             {   Exit        }
  766.                      else begin                          {Yes, so        }
  767.                         Col := Col + B;                  {   Move up Col }
  768.                         ShdBeMarked := True              {   Go again    }
  769.                      end {else}
  770.                   end {if Col}
  771.                until not ShdBeMarked
  772.             end {if Col<>0}
  773.          end {for K --once for each word in Key word list}
  774.       end; {procedure Ins}
  775.  
  776.    procedure BlankBrackets(var UC: Str255);                           {.CP18}
  777.    var
  778.       I,J,PosCut,
  779.       PosUnCut:       byte;
  780.    begin
  781.       if Cut <> '' then begin        {already in a bracket --check for close}
  782.          PosUnCut := pos(UnCut,UC);
  783.          if PosUnCut=0 then                  {no close}
  784.             for I := 1 to ord(UC[0]) do      {blank all of UC}
  785.                UC[I] := #32
  786.          else begin                          {has closer}
  787.             if UnCut = '*)' then
  788.                inc(PosUnCut);
  789.             for I := 1 to PosUnCut do        {blank UC to closer}
  790.                UC[I] := #32;
  791.             Cut := ''; UnCut := ''
  792.          end {else}
  793.       end; {if Cut}
  794.       while (pos(Cuts[1],UC)<>0) or                                   {.CP29}
  795.             (pos(Cuts[2],UC)<>0) or
  796.             (pos(Cuts[3],UC)<>0) do begin   {UC contains openers}
  797.          J := ord(UC[0]);
  798.          for I := 1 to 3 do begin               {find first opener}
  799.             PosCut := pos(Cuts[I],UC);
  800.             if (PosCut>0) and
  801.                (PosCut<J) then begin
  802.                   Cut := Cuts[I];
  803.                   UnCut := UnCuts[I];
  804.                   J := PosCut
  805.             end {if}
  806.          end; {for I}
  807.          PosCut := J;
  808.          PosUncut := pos(UnCut,copy(UC,succ(pos(Cut,UC)),255));
  809.          if PosUnCut<>0 then begin     {If there's a closer, find its posit}
  810.             PosUnCut := PosUnCut + PosCut;
  811.             if UnCut = '*)' then
  812.                inc(PosUnCut);
  813.             for I := PosCut to PosUnCut do            {blank UC in brackets}
  814.                UC[I] := #32;
  815.             Cut := '';                                {reset Cut & UnCut}
  816.             UnCut := ''
  817.          end {there's a closer}
  818.          else                                   {if no closer}
  819.             for I := PosCut to ord(UC[0]) do          {blank rest of UC}
  820.                UC[I] := #32;
  821.       end {while openers in UC}
  822.    end; {BlankBrackets}
  823.  
  824.    procedure ClearIdentifiers (var UC: Str255);                       {.CP29}
  825.    var
  826.       I:           byte;
  827.    begin
  828.       InMiddle := False; InHex := False;
  829.       for I := 1 to ord(UC[0]) do
  830.          if UC[I] = #32 then begin                                  {a blank}
  831.             InMiddle := False;
  832.             InHex := False
  833.          end {if blank}
  834.          else if UC[I] = '$' then begin                 {start of hex number}
  835.             InHex := True;
  836.             InMiddle := False;
  837.             UC[I] := #32
  838.          end {else $}
  839.          else
  840.             if InMiddle then begin                         {in an identifier}
  841.                if not (UC[I] in MiddleSet) then begin
  842.                   UC[I] := #32;
  843.                   InMiddle := False
  844.                end {if not UC}
  845.             end {if InMiddle}
  846.             else if InHex then begin                        {in a hex number}
  847.                if not (UC[I] in HexNumbers) then InHex := False;
  848.                if InHex or not (UC[I] in AtStart) then UC[I] := #32
  849.             end {else Hex number}
  850.             else if (UC[I] in AtStart) then InMiddle := True {start an ident}
  851.             else UC[I] := #32
  852.    end; {ClearIdentifiers}
  853.  
  854.    begin {Underline}                                                   {.CP9}
  855.       UC := Line;                                    {Prepare guide template}
  856.       for B := 1 to ord(UC[0]) do UC[B] := UpCase(UC[B]);      {All capitals}
  857.       BlankBrackets(UC);                   {Remove all comments & quotations}
  858.       ClearIdentifiers(UC);             {Remove everything not an identifier}
  859.       Ins(Line,UC,Opening,Closing)    {Insert printer chars around Key words}
  860.    end; {Underline}
  861.  
  862.    procedure PrintLine;               {Print one line}                {.CP26}
  863.    var
  864.       B,
  865.       RealLength:  byte;
  866.       Opener:      LineType;
  867.    begin
  868.       RealLength := ord(Line[0]) - 2;       {Length w/o pad or print symbols}
  869.       Opener := '';
  870.       if Mrk or XRef then Underline(Line);
  871.       if (NumberLines) then begin            {write line number or spaces}
  872.          if NoLine or (RealLength=0) then begin    {if a continuation    }
  873.             Opener := Opener + '     ';
  874.             if Mrk then
  875.                Opener := Opener + '       '            {spaces only      }
  876.             else
  877.                Opener := Opener + '  '
  878.          end {if NoLine}
  879.          else begin                                {if beginning new line}
  880.             Opener := Opener + StrgI(LineNumber,5);      {write line numb}
  881.             if Mrk then
  882.                Opener := Opener+ ' ' +StrgB(Depth,2) + '    ' {& depth}
  883.             else
  884.                Opener := Opener + '  ';                       {no depth}
  885.             NoLine := False
  886.          end {else --not NoLine}
  887.       end; {if Numberlines}
  888.       if XRef then                                                {.CP22}
  889.          ScanAndHash(UC,Line,LineNumber)                 {Scan for X-ref}
  890.       else begin
  891.          GotoXY(46,16);                           {Keep user entertained}
  892.          write(LineNumber:5)
  893.       end; {else not XRef}
  894.       Line := copy(Line,2,ord(Line[0])-2);                {remove padding}
  895.       if (IncMark[0]>#0) or (IncLine[0]>#0) then begin
  896.          for B := RealLength to pred(MaxLess) do
  897.              Line := Line + #32;
  898.          Line := Line + IncLine + IncMark;
  899.          IncLine := '';
  900.          IncState := OK;
  901.       end; {if IncMark}
  902.       if not XRefOnly then writeln(Lst,Opener,Line);        {Enfin! WRITE}
  903.       if LongOne then
  904.          NoLine := True
  905.       else begin
  906.          NoLine := False;
  907.          inc(LineNumber)
  908.       end {else if not NoLine}
  909.    end; {PrintLine}
  910.  
  911.    procedure TabSpace;      {make room for tabs (every 8 chars)}      {.CP15}
  912.    var
  913.       B,Col,Nchrs: byte;
  914.  
  915.       procedure StartLineEnd;
  916.       begin
  917.          LineEnd := '';
  918.          LongOne := True
  919.       end; {StartLineEnd}
  920.  
  921.    begin
  922.       if Line[1]=TabChr then begin    {turn ldg TabChr to Tab & strip others}
  923.          Line[1] := #9;
  924.          while Line[2]=TabChr do delete(Line,2,1)
  925.       end; {if Line[1]}
  926.       Col := 1;                                                       {.CP26}
  927.       while Col<= ord(Line[0]) do begin
  928.          if Line[Col]=#9 then begin                   {if Tab in that column}
  929.             Delete(Line,Col,1);                             {remove Tab char}
  930.             Nchrs := Col mod 8;
  931.             if Nchrs=0 then Nchrs := 8;
  932.             Nchrs := 9 - Nchrs;                  {number of blanks to insert}
  933.             for B := 1 to Nchrs do begin
  934.                insert(TabChr,Line,Col);                      {insert TabChrs}
  935.                if not LongOne then                      {Check if overlength}
  936.                   if ord(Line[0])>Max then StartLineEnd;
  937.             end; {for B}
  938.             Col := Col + pred(Nchrs);                {move Col to end of Tab}
  939.             if LongOne then begin                   {re-cut Line and LineEnd}
  940.                B := ord(Line[0]) - Nchrs;
  941.                while not (Line[B] in [#32,TabChr]) do dec(B);    {find blank}
  942.                Nchrs := ord(Line[0]) - B;
  943.                for B := 1 to Nchrs do begin                     {shift chars}
  944.                   LineEnd := Line[ord(line[0])] + LineEnd;
  945.                   delete(Line,ord(line[0]),1)
  946.                end {for B}
  947.             end {if LongOne}
  948.          end; {if Line[Col] is Tab}
  949.          inc(Col)                                             {increment Col}
  950.       end {while Col}
  951.    end; {TabSpace}
  952.  
  953.    procedure FixRemainder;                                            {.CP17}
  954.    var
  955.       B:           byte;
  956.    begin
  957.       while (LineEnd[1]=#32) and (ord(LineEnd[0])>0) do       {Strip leading}
  958.          delete(LineEnd,1,1);                           {blanks from LineEnd}
  959.       B := 1;
  960.       while (LineEnd[B]=TabChr) and (B<=ord(LineEnd[0])) do        {get past}
  961.          inc(B);                                                    {TabChrs}
  962.       while (LineEnd[B]=#32) and (ord(LineEnd[0])>=B) do      {strip further}
  963.          delete(LineEnd,B,1);                                        {blanks}
  964.       B := 1;
  965.       while (B<ord(Line[0])) and (Line[B]=' ') do begin      {Pad LineEnd to}
  966.          inc(B);                                                 {line it up}
  967.          LineEnd := ' ' + LineEnd
  968.       end {while (B<}
  969.    end; {FixRemainder}
  970.  
  971.    procedure DeTab; {turn initial Tab chars into blanks}              {.CP10}
  972.    var
  973.       B:           byte;
  974.    begin
  975.       for B := 1 to ord(Line[0])do
  976.          if Line[B]=TabChr then Line[B] := #32;
  977.    end; {DeTab}
  978.  
  979.    procedure CutIt(Mx: integer); {Cut line at last}                   {.CP16}
  980.    var                            {possible blank}
  981.       B,Col:       byte;
  982.       Temp:        Str255;
  983.    begin
  984.       B := Mx;
  985.       while (B>0) and (Line[B]<>' ') do dec(B); {Find last blank space}
  986.       Col := 1;
  987.       while (Col<=B) and (Line[Col]=' ') do inc(Col);       {find 1st non-sp}
  988.       if (Col>=B) then B := Mx;
  989.       Temp := copy(Line,1,pred(B));
  990.       delete(Line,1,pred(B));                                     {Chop line}
  991.       LineEnd := Line + LineEnd;                     {Remainder into LineEnd}
  992.       Line := Temp;
  993.       LongOne := True;                                             {Set flag}
  994.    end; {CutIt}
  995.  
  996.    procedure SetMax;                                                  {.CP13}
  997.  
  998.       procedure UseEliteForCondensed;
  999.       var
  1000.          I:   integer;
  1001.       begin
  1002.          Istring[CondB] := Istring[EliteB];
  1003.          Istring[CondE] := Istring[EliteE];
  1004.          for I := 1 to 3 do begin
  1005.             Inst[CondB,I] := Inst[EliteB,I];
  1006.             Inst[CondE,I] := Inst[EliteE,I]
  1007.          end; {for I}
  1008.       end; {UseEliteForCondensed}
  1009.  
  1010.       function CondensedElite: boolean; {T iff CondB = EliteB}         {.CP7}
  1011.       var
  1012.          I:   integer;
  1013.       begin
  1014.          CondensedElite := True;
  1015.          for I := 1 to 3 do
  1016.             if (Inst[EliteB,I]<>Inst[CondB,I]) then
  1017.                CondensedElite := False
  1018.       end; {CondensedElite}
  1019.  
  1020.    begin {SetMax}                                                     {.CP32}
  1021.       if not GotPrnData then
  1022.          if NumberLines
  1023.             then Max := 68
  1024.             else Max := 79
  1025.       else begin
  1026.          if Wide
  1027.             then Max := 131
  1028.             else Max := 79;
  1029.          if NumberLines and Condensed then begin
  1030.             if CondensedElite then
  1031.                Max := 120             {if so then presume both are condensed}
  1032.             else if Elite then begin  {if we have both and they're different}
  1033.                if Wide
  1034.                   then Max := 120
  1035.                   else Max := 84
  1036.             end {else if E & C}
  1037.             else                         {if we have Condensed but not Elite}
  1038.                Max := Max - 11
  1039.          end; {if NumberLines and Condensed}
  1040.          if Elite and (not Condensed) then begin
  1041.             UseEliteForCondensed;
  1042.             if Wide then Max := 95;
  1043.             if NumberLines then Max := 84
  1044.          end {if Elite & not Condensed}
  1045.          else if not (Elite or Condensed) then begin
  1046.             if wide then Max := 79;
  1047.             if NumberLines then Max := 68
  1048.          end; {if neither}
  1049.          if NumberLines and not Mrk then Max := Max + 4
  1050.       end; {else GotPrnData}
  1051.    end; {SetMax}
  1052.  
  1053.    procedure XRBillboard;                                              {.CP9}
  1054.    begin
  1055.       if XRef then
  1056.          WriteCRT('Program lines:',14,15,Bright)
  1057.       else begin
  1058.          WriteCRT('--- Not Cross-Referencing ---',14,26,Bright);
  1059.          WriteCRT('    Printing Line: ',16,26,Bright)
  1060.       end {else}
  1061.    end; {XRBillboard}
  1062.  
  1063.    procedure TotItUp;                                                  {.CP6}
  1064.    begin
  1065.       GotoXY(49,14); write('Identifiers: ',ScanCount:5);
  1066.       GotoXY(49,15); write('Procedures:  ',Pcount:5);
  1067.       GotoXY(49,16); write('Occurrences: ',Occur:5)
  1068.    end; {TotItUp}
  1069.  
  1070.    procedure MarkInc;  {insert INC marker in Line}                    {.CP15}
  1071.    var
  1072.       B,Indent:    byte;
  1073.    begin
  1074.       IncMark := '';
  1075.       for B := 2 to IFN do IncMark := IncMark + '*';
  1076.       case IncState of
  1077.          Started:  IncLine := '<=== Including '
  1078.                               + IFileName[IFN] + ' ';
  1079.          Ended:    IncLine := '<=== Finished '
  1080.                               + IFileName[succ(IFN)] + ' *';
  1081.          TooDeep:  IncLine := '<=== Too many includes.  Can''t include it.';
  1082.          CantFind: Incline := '<=== Couldn''t find it.';
  1083.       end; {case}
  1084.    end; {MarkInc}
  1085.  
  1086.    procedure Include;                                                 {.CP10}
  1087.    var
  1088.       B,E:         byte;
  1089.       ComString:   CMD;
  1090.       IncFile:     boolean;
  1091.  
  1092.       function DepthOK: boolean;
  1093.       begin
  1094.          DepthOK := IFN < NoIncFiles
  1095.       end; {DepthOK}
  1096.  
  1097.       procedure TryToOpen(FName: LineType; var F: text);                 {.CP10}
  1098.       begin
  1099.          assign(F,FName);
  1100.          {$I-}
  1101.          reset(F);
  1102.          {$I+}
  1103.          if IOresult=0
  1104.             then IncState := Started
  1105.             else IncState := CantFind
  1106.       end; {TryToOpen}
  1107.  
  1108.    begin  {Include}                                                   {.CP13}
  1109.       B := Pos('{$'+'I',Line) + 3;
  1110.       E := Pos('}',Line);
  1111.       if (E<>0) and (E>B) then begin
  1112.          ComString := Copy(Line,B,E-B);              {Peel out string}
  1113.          if (pos('-',ComString)<>0) or (pos('+',ComString)<>0)
  1114.             then IncFile := False         {Check whether include instruction}
  1115.             else IncFile := True
  1116.       end {if E...}
  1117.       else begin
  1118.          ComString := '';
  1119.          IncFile := False
  1120.       end; {else}
  1121.       if IncFile then begin                        {if an INCLUDE}     {.CP7}
  1122.          while (ComString[1]=#32) and (ComString[0]>#0) do
  1123.             delete(ComString,1,1);                    {strip leading blanks }
  1124.          while ComString[ord(ComString[0])]=#32 do    {strip trailing blanks}
  1125.             dec(ComString[0]);
  1126.          inc(IFN);                                     {move a level down   }
  1127.          IFileName[IFN] := ComString;
  1128.          if DepthOK then begin                         {if depth left}{.CP10}
  1129.             FixUpFileName(IFileName[IFN]);
  1130.             TryToOpen(IFileName[IFN],IFil[IFN]);          {try name as found}
  1131.             if IncState=CantFind then begin
  1132.                while (pos(':',IFileName[IFN])<>0)         {if no go as found}
  1133.                      or (pos('\',IFileName[IFN])<>0) do
  1134.                         delete(IFileName[IFN],1,1);   {try same path as main}
  1135.                IFileName[IFN] := PathSign + IFileName[IFN];
  1136.                TryToOpen(IFileName[IFN],IFil[IFN]);
  1137.             end; {if couldn't find}
  1138.             if IncState=CantFind then    {if still no go, search path}{.CP11}
  1139.                if FindFile(IFileName[IFN]) then begin    {if found}
  1140.                   Assign(IFil[IFN],IFileName[IFN]);         {set up new file}
  1141.                   Reset(IFil[IFN]);
  1142.                   IncState := Started
  1143.                end; {if file found}
  1144.             if IncState=Started then             {if file found (somewhere)}
  1145.                CenterCRT('Including ' + IFileName[IFN],
  1146.                          12,Bright,Inside)    {showing where found}
  1147.             else begin                         {If file not found     {.CP11}
  1148.                Blank(12,12);                                 {report failure}
  1149.                FixUpFileName(IFileName[IFN]);
  1150.                CenterCRT('Can''t find '+IFileName[IFN],
  1151.                           12,Bright,Inside);
  1152.                dec(IFN);
  1153.             end; {if can't find it}
  1154.             while (pos(':',IFileName[IFN])<>0)           {strip pathmarks}
  1155.                or (pos('\',IFileName[IFN])<>0) do        {for printout}
  1156.                   delete(IFileName[IFN],1,1);
  1157.          end {if depth left}
  1158.          else begin                             {report no depth left} {.CP8}
  1159.             CenterCRT('Too many Include files',12,Bright,Inside);
  1160.             dec(IFN);
  1161.             IncState := TooDeep
  1162.          end; {else --no depth left}
  1163.          MarkInc;
  1164.       end {if IncFile}
  1165.    end; {Include}
  1166.  
  1167.    procedure CutAndPrint;                                             {.CP24}
  1168.    begin
  1169.       if LongOne then begin
  1170.          Line := LineEnd;
  1171.          LongOne := False
  1172.       end {if LongOne}
  1173.       else begin
  1174.          readln(IFil[IFN],Line);
  1175.          if EOF(IFil[IFN]) and (IFN>1) then begin
  1176.             CloseCarefully(IFil[IFN]);
  1177.             dec(IFN);
  1178.             IncState := Ended;
  1179.             MarkInc
  1180.          end; {if Eof}
  1181.          if pos('{',Line)<>0 then begin
  1182.             if pos('{.',Line)<>0 then begin
  1183.                if pos('{'+'.H',Line)<>0 then GetHeaderInstruction(Line);
  1184.                if (pos('{'+'.C',Line)<>0) or (pos('{'+'.P',Line)<>0) then
  1185.                   PrintControl(PageLineNumber);
  1186.             end; {if '{.'}
  1187.             if Pos('{'+'$I',Line)=1 then Include
  1188.          end; {if '{'}
  1189.          if PageLineNumber=-1 then PrintHeader(PageLineNumber);
  1190.       end; {else --read next line}
  1191.       LineEnd := '';                                                  {.CP15}
  1192.       MaxLess := Max - ord(IncMark[0]) - ord(IncLine[0]);
  1193.       if ord(Line[0])>MaxLess then CutIt(MaxLess);{CutIt sets LongOne = True}
  1194.       if pos(#9,Line)<>0 then TabSpace;
  1195.       if ord(LineEnd[0])>0 then FixRemainder; {pad LineEnd w matching blanks}
  1196.       if Pos(TabChr,Line)<>0 then DeTab;
  1197.       Line := ' ' + Line + ' ';                   {Pad line w blanks at ends}
  1198.       inc(PageLineNumber);
  1199.       Pager := PageLineNumber;
  1200.       if (PageLineNumber>MaxLin) and not XRefOnly then begin
  1201.          NewPage(Pager);
  1202.          PrintHeader(PageLineNumber);
  1203.       end; {if (PageLine.. }
  1204.       PrintLine;
  1205.    end; {CutAndPrint}
  1206.  
  1207.    procedure Initialize;                                              {.CP10}
  1208.    var
  1209.       HS: HdSegType;
  1210.       K: integer;
  1211.    begin
  1212.       for K := 1 to NoIncFiles do IFileName[K] := '';
  1213.       for K := 1 to 20 do begin
  1214.          RecDepth[K] := 0;
  1215.          CaseDepth[K] := 0
  1216.       end; {for K}
  1217.       Occur := 0; ScanCount := 0; PCount := 0;                        {.CP14}
  1218.       for K := 0 to TableSize do T[K] := Nil; Longest := 0;
  1219.       OpLen := ord(Opening[0]); ClLen := ord(Closing[0]);
  1220.       Cut := ''; UnCut := ''; Depth := 0; InRec := 0;
  1221.       LongOne := False; NoLine := False; Enough := False;
  1222.       Cuts[1] := '(*'; Cuts[2] := '{'; Cuts[3] := #39;
  1223.       UnCuts[1] := '*)'; UnCuts[2] := '}'; UnCuts[3] := #39;
  1224.       LineNumber := 1; Page := 1; IncState := OK;
  1225.       IFN := 1; assign(IFil[1],FileName); FileName := Shortened(FileName);
  1226.       MakeFirstHeader(IFil[1]);
  1227.       IncMark := '';IncLine := '';
  1228.       if Inst[EliteB,1]=255 then Elite := False else Elite := True;
  1229.       if Inst[CondB,1]=255  then Condensed := False else Condensed := True
  1230.    end; {Initialize}
  1231.  
  1232. begin {ListIt}                                                        {.CP30}
  1233.    ReadingMatterI;
  1234.    Enough := Escape;
  1235.    if not Enough then begin
  1236.       assign(Lst,OutputDevice); rewrite(Lst);
  1237.       CursorOff;
  1238.       Initialize;
  1239.       SetMax;
  1240.       if FFeed then NewPage(1);
  1241.       if not XRefOnly then PageLineNumber := -1;
  1242.       XRBillboard;
  1243.       while (LongOne or not EOF(IFil[IFN])) and not Enough do begin
  1244.          CutAndPrint;
  1245.          Enough := Escape
  1246.       end; {while}
  1247.       for B := IFN to 1 do CloseCarefully(IFil[IFN]);    {Close source files}
  1248.       if not XRefOnly then NewPage(Pager);
  1249.       if XRef and not Enough then begin
  1250.          XRefOnly := True;          {used as a flag  --over clever, no doubt}
  1251.          ReadingMatterII;
  1252.          PrintTable;
  1253.          TotItUp;
  1254.          NewPage(Pager)
  1255.       end; {if XRef and not Enough}
  1256.       if Wide then write(Lst,Istring[CondE]);    {Put printer back to normal}
  1257.       if Numberlines then write(Lst,Istring[EliteE])
  1258.    end {if not Enough}
  1259. end; {ListIt}
  1260.  
  1261. End. {Unit PXLLIST}
  1262.